//package com.xzgj.fmmall.controller;
//
//import com.google.zxing.WriterException;
//import com.google.zxing.client.j2se.MatrixToImageWriter;
//import com.xzgj.fmmall.vo.ResultVO;
//import org.json.JSONObject;
//import org.springframework.web.bind.annotation.*;
//
//import java.util.UUID;
//import com.google.zxing.BarcodeFormat;
//import com.google.zxing.EncodeHintType;
//import com.google.zxing.MultiFormatWriter;
//import com.google.zxing.common.BitMatrix;
//import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
//import javax.servlet.http.HttpServletResponse;
//import java.io.IOException;
//import java.util.HashMap;
//import java.util.Map;
//
//@RestController
//@RequestMapping("/qrlogin")
//public class QrLoginController {
//
//    @RequestMapping(value = "/generate",method = RequestMethod.GET)
//    public void generateQrCode(HttpServletResponse response) throws IOException, WriterException {
//        // 生成唯一标识符
//        String uuid = UUID.randomUUID().toString();
//        // 构建二维码内容，这里可以包含更多信息，如应用标识、登录过期时间等
//        String qrContent = "https://www.baidu.com?uuid=" + uuid;
//        // 设置二维码参数
//        int width = 300;
//        int height = 300;
//        Map<EncodeHintType, Object> hints = new HashMap<>();
//        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
//        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
//        // 生成二维码矩阵
//        BitMatrix bitMatrix = new MultiFormatWriter().encode(qrContent, BarcodeFormat.QR_CODE, width, height, hints);
//        // 将二维码矩阵输出为图片格式
//        response.setContentType("image/png");
//        MatrixToImageWriter.writeToStream(bitMatrix, "PNG", response.getOutputStream());
//    }
//
//    // 后续可以添加验证登录等其他相关方法
//    //...
////    @RequestMapping(path = "/scan", method = RequestMethod.POST)
////    @ResponseBody
////    public ResultVO scanQrCodeImg(@RequestParam String uuid) {
////        JSONObject data = loginService.scanQrCodeImg(uuid);
////        if (data.getBoolean("valid")) {
////            return ResultVO.createResponse("扫码成功", data);
////        }
////        return Response.createErrorResponse("二维码已失效");
////    }
////
////    @RequestMapping(path = "/confirm", method = RequestMethod.POST)
////    @ResponseBody
////    public Response confirmLogin(@RequestParam String uuid) {
////        boolean logged = loginService.confirmLogin(uuid);
////        String msg = logged ? "登录成功!" : "二维码已失效!";
////        return Response.createResponse(msg, logged);
////    }
//
//}

package com.xzgj.fmmall.controller;

import cn.hutool.cache.CacheUtil;
import cn.hutool.cache.impl.TimedCache;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.qrcode.QrCodeUtil;
import cn.hutool.extra.qrcode.QrConfig;
import com.xzgj.fmmall.domain.entity.UserEntity;
import com.xzgj.fmmall.domain.pojo.SessionPojo;
import com.xzgj.fmmall.domain.result.AjaxResult;
import com.xzgj.fmmall.service.UserService;
import com.xzgj.fmmall.service.impl.QrUserService;
import com.xzgj.fmmall.vo.UserVO;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.HashMap;
import java.util.Map;

/**
 * 用户登录
 */
@Slf4j
@RestController
@RequestMapping(value = "/user")
@Api(value = "提供二维码扫描登录的相关接口",tags = "二维码扫描登录管理")
public class QrLoginController {

    @Autowired
    private QrUserService qrUserService;

    /**
     * 缓存放二维码会话，设置1分钟过期
     */
    private TimedCache qrCodeSession= CacheUtil.newTimedCache(1000*60);

    /**
     * 存储token信息
     */
    private TimedCache mobileTokenSession=CacheUtil.newTimedCache(1000*60);


    /**
     * 用户手机端登录方法
     * @return
     */
    @PostMapping(value = "/loginMobile")
    public AjaxResult<Map<String,String>> loginMobile(@RequestBody UserEntity userForm){
        UserEntity userEntity=qrUserService.login(userForm);
        //登录成功
        if(ObjectUtil.isNotNull(userEntity)){
            AjaxResult ajaxResult = AjaxResult.SUCCESS;
            Map<String,String> resultMap=new HashMap<>();
            resultMap.put("username",userEntity.getUsername());
            String tokenId=IdUtil.objectId();
            resultMap.put("token",tokenId);
            log.debug("token={}",tokenId);
            ajaxResult.setData(resultMap);
            //存储到缓存中
            mobileTokenSession.put(tokenId,userEntity);
            return ajaxResult;
        }else{ //登录失败
            return AjaxResult.Fail;
        }
    }


    /**
     * 生成PC端登录二维码
     * @return
     */
    @GetMapping(value = "/pcQrCode")
    public Mono<AjaxResult<Map<String,String>>> pcQrCode(){
        return Mono.create((sink)->{
            //生成会话编号
            String sessionId= IdUtil.objectId();
            log.debug("sessionId={}",sessionId);
            SessionPojo sessionPojo=new SessionPojo();
            sessionPojo.setSessionId(sessionId);
            //0 二维码 生成状态 ，1 扫码状态 2 登录状态
            sessionPojo.setStatus(0);

            //生成base64二维码
            QrConfig qrConfig=new QrConfig();
            qrConfig.setWidth(300);
            qrConfig.setHeight(300);
            String base64Code=QrCodeUtil.generateAsBase64(sessionId, qrConfig,"jpeg");

            //绑定返回体数据
            AjaxResult<Map<String,String>> ajaxResult=AjaxResult.SUCCESS;
            Map<String,String> resultData=new HashMap<>();
            resultData.put("sessionId",sessionId);
            resultData.put("base64Code",base64Code);
            ajaxResult.setData(resultData);

            //存入缓存
            qrCodeSession.put(sessionId,sessionPojo);

            sink.success(ajaxResult);
        });
    }


    /**
     * 监听二维码 session 状态
     * @param sessionId
     * @return
     */
    @GetMapping(value = "/getSessionStatus",produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Mono<AjaxResult<SessionPojo>> getSessionStatus(String sessionId){
        return Mono.create((sink)->{
            SessionPojo sessionPojo =(SessionPojo)qrCodeSession.get(sessionId);
            AjaxResult ajaxResult=AjaxResult.SUCCESS;
            if(ObjectUtil.isNull(sessionPojo)){
                sessionPojo=new SessionPojo();
                sessionPojo.setSessionId(sessionId);
                //0 二维码 生成状态 ，1 扫码成功 2 登录成功  -1 sessionId过期失效
                sessionPojo.setStatus(-1);
            }
            ajaxResult.setData(sessionPojo);
            sink.success(ajaxResult);
        });
    }


    /**
     * 扫码二维码成功
     * @return
     */
    @PostMapping(value = "/mobileScanOk")
    public Mono<AjaxResult> mobileScanOk(ServerWebExchange exchange)
    {

        return exchange.getFormData().flatMap((formData)->{
            //判断二维码session是否有效
            String sessionId = formData.getFirst("sessionId");
            String token=formData.getFirst("token");

            SessionPojo sessionPojo = (SessionPojo) qrCodeSession.get(sessionId);
            if(ObjectUtil.isNull(sessionPojo)){
                AjaxResult ajaxResult=AjaxResult.Fail;
                ajaxResult.setMsg("二维码已失效");
                return Mono.just(ajaxResult);
            }

            //判断token是否有效
            UserEntity userEntity = (UserEntity) mobileTokenSession.get(token);

            //0 二维码 生成状态 ，1 扫码成功 2 登录成功  -1 sessionId过期失效
            mobileTokenSession.get(token);
            sessionPojo.setStatus(1);
            sessionPojo.setUsername(userEntity.getUsername());
            AjaxResult ajaxResult=AjaxResult.SUCCESS;
            ajaxResult.setMsg("扫描成功，等待手机端确认操作");
            return Mono.just(ajaxResult);
        });


    }

    /**
     * 手机端确认登录
     * @return
     */
    @PostMapping(value = "/mobileOkPcLogin")
    public Mono<AjaxResult> mobileOkPcLogin(ServerWebExchange exchange){

        return exchange.getFormData().flatMap(formData -> {
            String sessionId = formData.getFirst("sessionId");
            String token=formData.getFirst("token");

            //判断二维码session是否有效
            SessionPojo sessionPojo = (SessionPojo) qrCodeSession.get(sessionId);
            if (ObjectUtil.isNull(sessionPojo)) {
                AjaxResult ajaxResult = AjaxResult.Fail;
                ajaxResult.setMsg("二维码已失效");
                return Mono.just(ajaxResult);
            }

            //判断token是否有效
            UserEntity userEntity = (UserEntity) mobileTokenSession.get(token);
            if (ObjectUtil.isNull(userEntity)) {
                AjaxResult ajaxResult = AjaxResult.Fail;
                ajaxResult.setMsg("用户信息验证失效");
                return Mono.just(ajaxResult);
            }

            //修改二维码session对象状态
            //0 二维码 生成状态 ，1 扫码成功 2 登录成功  -1 sessionId过期失效
            sessionPojo.setUsername(userEntity.getUsername());
            sessionPojo.setStatus(2);

            AjaxResult ajaxResult = AjaxResult.SUCCESS;
            ajaxResult.setMsg("PC登录成功");
            return Mono.just(ajaxResult);
        });

    }
}

